package com.warm.orm.eq.sys.mapper.impl;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.easy.query.api4j.client.EasyQuery;
import com.easy.query.api4j.select.Queryable;
import com.easy.query.api4j.select.Queryable3;
import com.easy.query.api4j.select.Queryable4;
import com.easy.query.core.enums.SQLExecuteStrategyEnum;
import com.easy.query.solon.annotation.Db;
import com.warm.orm.domain.PropertySort;
import com.warm.orm.domain.sys.*;
import com.warm.orm.eq.sys.mapper.SysRoleMapper;
import org.noear.solon.annotation.Component;

import java.util.List;
import java.util.Map;

@Component
public class SysRoleMapperImpl implements SysRoleMapper {

    @Db
    private EasyQuery easyQuery;

    private Queryable3<SysRole, SysUserRole, SysUser> buildQueryByUser(SysUser sysUser) {
        return this.easyQuery.queryable(SysRole.class)
                .leftJoin(SysUserRole.class, (t, t1) -> t1.eq(t, SysUserRole::getRoleId, SysRole::getRoleId))
                .leftJoin(SysUser.class, (t, t1, t2) -> t2.eq(t1, SysUser::getUserId, SysUserRole::getUserId))
                .where((t, t1, t2) -> t2
                        .eq(ObjUtil.isNotNull(sysUser.getUserId()), SysUser::getUserId, sysUser.getUserId())
                        .like(StrUtil.isNotBlank(sysUser.getUserName()), SysUser::getUserName, sysUser.getUserName()));
    }

    private Queryable4<SysRole, SysUserRole, SysUser, SysDept> buildQueryByRole(SysRole sysRole) {
        String beginTime = (String) sysRole.getParams().get("beginTime");
        String endTime = (String) sysRole.getParams().get("endTime");

        // from sys_role r
        return this.easyQuery.queryable(SysRole.class)
                // left join sys_user_role user_role on user_role.role_id = r.role_id
                .leftJoin(SysUserRole.class, (t, t1) -> t1.eq(t, SysUserRole::getRoleId, SysRole::getRoleId))
                // left join sys_user u on u.user_id = user_role.user_id
                .leftJoin(SysUser.class, (t, t1, t2) -> t2.eq(t1, SysUser::getUserId, SysUserRole::getRoleId))
                // left join sys_dept d on u.dept_id = d.dept_id
                .leftJoin(SysDept.class, (t, t1, t2, t3) -> t3.eq(t2, SysDept::getDeptId, SysUser::getDeptId))
                // where r.del_flag = '0'
                .where((t, t1, t2, t3) -> t
                        // AND r.role_id = #{roleId}
                        .eq(ObjUtil.isNotNull(sysRole.getRoleId()), SysRole::getRoleId, sysRole.getRoleId())
                        // AND r.role_name like concat('%', #{roleName}, '%')
                        .like(StrUtil.isNotBlank(sysRole.getRoleName()), SysRole::getRoleName, sysRole.getRoleName())
                        // AND r.status = #{status}
                        .eq(StrUtil.isNotBlank(sysRole.getStatus()), SysRole::getStatus, sysRole.getStatus())
                        // AND r.role_key like concat('%', #{roleKey}, '%')
                        .like(StrUtil.isNotBlank(sysRole.getRoleKey()), SysRole::getRoleKey, sysRole.getRoleKey())
                        // and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
                        .and(ObjUtil.isNotNull(beginTime),
                                o -> o.sqlNativeSegment("date_format({0}, ''%y%m%d'') >= date_format({1}, ''%y%m%d'')",
                                        s -> s.expression(SysRole::getCreateTime).value(beginTime)
                                )
                        )
                        // AND date_format(r.create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d')
                        .and(ObjUtil.isNotNull(endTime),
                                o -> o.sqlNativeSegment("date_format({0}, ''%y%m%d'') <= date_format({1}, ''%y%m%d'')",
                                        s -> s.expression(SysRole::getCreateTime).value(endTime)
                                )
                        )
                );
    }

    /**
     * 根据条件分页查询角色数据
     *
     * @param role 角色信息
     * @return 角色数据集合信息
     */
    @Override
    public List<SysRole> selectRoleList(SysRole role) {
        return this.easyQuery.queryable(SysRole.class)
                .orderByObject(new PropertySort("roleSort", Boolean.TRUE))
                .toList();
    }

    /**
     * 根据用户ID查询角色
     *
     * @param userId 用户ID
     * @return 角色列表
     */
    @Override
    public List<SysRole> selectRolePermissionByUserId(Long userId) {
        // from sys_role r
        //     left join sys_user_role user_role on user_role.role_id = r.role_id
        //     left join sys_user u on u.user_id = user_role.user_id
        return this.buildQueryByUser(new SysUser(userId))
                .toList();
    }

    /**
     * 查询所有角色
     *
     * @return 角色列表
     */
    @Override
    public List<SysRole> selectRoleAll() {
        return this.buildQueryByRole(new SysRole())
                .toList();
    }

    /**
     * 根据用户ID获取角色选择框列表
     *
     * @param userId 用户ID
     * @return 选中角色ID列表
     */
    @Override
    public List<Long> selectRoleListByUserId(Long userId) {
        // from sys_role r
        //     left join sys_user_role user_role on user_role.role_id = r.role_id
        //     left join sys_user u on u.user_id = user_role.user_id
        return buildQueryByUser(new SysUser(userId))
                // select r.role_id
                .select(Long.class, t1 -> t1.column(SysRole::getRoleId))
                .toList();
    }

    /**
     * 通过角色ID查询角色
     *
     * @param roleId 角色ID
     * @return 角色对象信息
     */
    @Override
    public SysRole selectRoleById(Long roleId) {
        return this.buildQueryByRole(new SysRole(roleId))
                .firstOrNull();
    }

    /**
     * 根据用户ID查询角色
     *
     * @param userName 用户名
     * @return 角色列表
     */
    @Override
    public List<SysRole> selectRolesByUserName(String userName) {
        SysUser sysUser = new SysUser();
        sysUser.setUserName(userName);
        return buildQueryByUser(sysUser).select(SysRole.class).toList();
    }

    /**
     * 校验角色名称是否唯一
     *
     * @param roleName 角色名称
     * @return 角色信息
     */
    @Override
    public SysRole checkRoleNameUnique(String roleName) {
        SysRole sysRole = new SysRole();
        sysRole.setRoleName(roleName);
        return this.buildQueryByRole(sysRole)
                // limit 1
                .firstOrNull();
    }

    /**
     * 校验角色权限是否唯一
     *
     * @param roleKey 角色权限
     * @return 角色信息
     */
    @Override
    public SysRole checkRoleKeyUnique(String roleKey) {
        SysRole sysRole = new SysRole();
        sysRole.setRoleKey(roleKey);
        return this.buildQueryByRole(sysRole)
                // limit 1
                .firstOrNull();
    }

    /**
     * 修改角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public int updateRole(SysRole role) {
        return (int) this.easyQuery.updatable(role).setSQLStrategy(SQLExecuteStrategyEnum.ONLY_NOT_NULL_COLUMNS).executeRows();
    }

    /**
     * 新增角色信息
     *
     * @param role 角色信息
     * @return 结果
     */
    @Override
    public int insertRole(SysRole role) {
        return (int) this.easyQuery.insertable(role).executeRows();
    }

    /**
     * 通过角色ID删除角色
     *
     * @param roleId 角色ID
     * @return 结果
     */
    @Override
    public int deleteRoleById(Long roleId) {
        return (int) this.easyQuery.deletable(SysUser.class).whereById(roleId).executeRows();
    }

    /**
     * 批量删除角色信息
     *
     * @param roleIds 需要删除的角色ID
     * @return 结果
     */
    @Override
    public int deleteRoleByIds(Long[] roleIds) {
        return (int) this.easyQuery.deletable(SysUser.class).whereByIds((List<Long>) Convert.toList(roleIds)).executeRows();
    }
}
